package com.wenlin.myproduction.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;

import com.wenlin.myproduction.R;
import com.wenlin.myproduction.bean.Block;
import com.wenlin.myproduction.bean.NumData;
import com.wenlin.myproduction.bean.RecordBean;
import com.wenlin.myproduction.util.Checker;
import com.wenlin.myproduction.util.LogUtils;
import com.wenlin.myproduction.util.ToastUtils;
import com.wenlin.myproduction.util.UI;

import java.util.ArrayList;
import java.util.List;

public class ShuDuView extends View {
    private static final float RADIUS = 5;
    private static final String[] rows = {"1", "2", "3", "4", "5", "6", "7", "8", "9"};
    //    private static final String[] rows = {"A", "B", "C", "D", "E", "F", "G", "H", "I"};
    private Paint paint;
    private TextPaint textPaint, textPaintBold;
    private Rect rect;
    private float blockLong;
    @ColorInt
    private int colorWhite = UI.getColor(R.color.myWhite);
    @ColorInt
    private int colorBlack = UI.getColor(R.color.myTitle);
    @ColorInt
    private int colorGray = UI.getColor(R.color.myGray);
    @ColorInt
    private int colorBlue = UI.getColor(R.color.myBlue);
    @ColorInt
    private int colorGray2 = UI.getColor(R.color.myGray2);
    private int current;
    private int[][] arrTitle = new int[9][9];
    private int[][] arrAnswer = new int[9][9];
    private List<NumData> listNumData;
    private NumData numData;
    private List<RecordBean> listRecord;
    private boolean editMode;
    private int allStep;
    private int lastStep;
    private boolean isResolve = false;

    public ShuDuView(Context context) {
        this(context, null);
    }

    public ShuDuView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setColor(colorBlack);

        textPaint = new TextPaint();
        textPaint.setAntiAlias(true);
        textPaint.setDither(true);
        textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        textPaint.setColor(colorBlack);
        textPaint.setTextSize(UI.getPx(R.dimen.wpx40));

        textPaintBold = new TextPaint();
        textPaintBold.setAntiAlias(true);
        textPaintBold.setDither(true);
        textPaintBold.setStyle(Paint.Style.FILL_AND_STROKE);
        textPaintBold.setColor(colorBlack);
        textPaintBold.setTextSize(UI.getPx(R.dimen.wpx80));

        rect = new Rect();
        listRecord = new ArrayList<>();
        setBlocks();
    }

    public void setEdit(boolean canEdit) {
        editMode = canEdit;
    }

    public void setData(RecordBean recordBean) {
        arrAnswer = recordBean.getArr();
        numData = recordBean.getNumData();
        if (Checker.notNull(numData)) {
            current = recordBean.getNumData().getNum();
        }
        invalidate();
    }

    public void setRecords(List<RecordBean> list) {
        listRecord = list;
        invalidate();
    }

    private void setBlocks() {
        //困难难度
//        String str = "086900170"
//                + "000000000"
//                + "040803002"
//                + "050008009"
//                + "002060300"
//                + "900100040"
//                + "200406090"
//                + "000000000"
//                + "061007820";
//        String str = "900800000"
//                + "000001005"
//                + "100960004"
//                + "005000006"
//                + "090080410"
//                + "000003078"
//                + "082100340"
//                + "010420060"
//                + "060008052";
        String str = "009748000"
                +"700000000"
                +"020109000"
                +"007000240"
                +"064010590"
                +"098000300"
                +"000803020"
                +"000000006"
                +"000275900"
                ;
        for (int i = 0; i < 9; i++) {
            String rowStr = str.substring(i * 9, i * 9 + 9);
            for (int j = 0; j < 9; j++) {
                String s = rowStr.substring(j, j + 1);
                arrTitle[i][j] = Integer.parseInt(s);
                arrAnswer[i][j] = Integer.parseInt(s);
            }
        }
        RecordBean recordBean = new RecordBean(1, arrAnswer, null);
        listRecord.add(recordBean);
    }



    private void poJie(int[][] arrAnswer) {
        while (!isSuccess(arrAnswer)) {
            for (int i = 0; i < 9; i++) {
                for (int j = 0; j < 9; j++) {
                    int cell = arrAnswer[i][j];
                    if (cell == 0) continue;
                    for (int num = 1; num <= 9; num++) {
                        arrAnswer[i][j] = num;
                        if (checkRule(i, j)) {
                            poJie(arrAnswer);
                            if (isResolve) return;
                        } else {
                            arrAnswer[i][j] = 0;
                        }
                    }
                    arrAnswer[i][j] = 0;
                    return;
                }
            }
        }
        isResolve = true;
        LogUtils.e("Figure out!");
        invalidate();
    }

    private boolean checkRule(int x, int y) {
        //检查行
        int check = 0;
        for (int i = 0; i < 9; i++) {
            int cell = arrAnswer[x][i];
            if (cell == 0) continue;
            if (cell >= 1 & cell <= 9) {
                if (testBit(check, cell)) {
                    return false;
                } else {
                    check = setBit(check, cell);
                }
            }
        }
        //检查列
        check = 0;
        for (int i = 0; i < 9; i++) {
            int cell = arrAnswer[i][y];
            if (cell == 0) continue;
            if (cell >= 1 && cell <= 9) {
                if (testBit(check, cell)) {
                    return false;
                } else {
                    check = setBit(check, cell);
                }
            }
        }
        //检查宫
        check = 0;
        int xBlock = x / 3;
        int yBlock = y / 3;
        for (int i = xBlock * 3; i < xBlock * 3 + 3; i++) {
            for (int j = yBlock * 3; j < yBlock * 3 + 3; j++) {
                int cell = arrAnswer[i][j];
                if (cell == 0) continue;
                if (cell >= 1 && cell <= 9) {
                    if (testBit(check, cell)) {//
                        return false;
                    } else {//
                        check = setBit(check, cell);
                    }
                }
            }
        }
        return true;
    }

    private boolean testBit(int check, int number) {
        if ((check & (1 << (number - 1))) > 0) {
            return true;
        }
        return false;
    }

    private int setBit(int check, int number) {
        return check | (1 << (number - 1));
    }


    private int getStep() {
        int step = 0;
        listNumData = new ArrayList<>();
        //先尝试找出能够确定的数字
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                int n = arrAnswer[i][j];
                if (n == 0) {
                    List<Integer> list = new ArrayList<>();
                    for (int k = 0; k < 9; k++) {
                        int num = k + 1;
                        if (checkRow(num, i) && checkColumn(num, j) && checkGong(num, i, j)) {
                            list.add(num);
                        }
                    }
                    if (list.size() == 1) {
                        arrAnswer[i][j] = list.get(0);
                        step++;
                    }
                }
            }
        }
        //反证法，尝试将数字放入九宫格，找到只能放在唯一位置的情况
        for (int i = 0; i < 9; i++) {
            int num = i + 1;
            List<Block> list = new ArrayList<>();
            for (int j = 0; j < 9; j++) {
                for (int k = 0; k < 9; k++) {
                    int n = arrAnswer[j][k];//7,4
                    if (n == 0) {
                        int gongRow = j / 3;//2
                        int gongColumn = k / 3;//1
                        boolean otherTwoRowHas = true;
                        boolean otherTwoColumnHas = true;
                        boolean gongRowNull = false;
                        boolean gongColumnNull = false;
                        for (int l = gongRow * 3; l < gongRow * 3 + 3; l++) {
                            if (l == j) {
                                if (arrAnswer[j][gongColumn * 3] == 0 && arrAnswer[j][gongColumn * 3 + 1] == 0 && arrAnswer[j][gongColumn * 3 + 2] == 0)
                                    gongRowNull = true;
                            } else if (checkRow(num, l)) {
                                otherTwoRowHas = false;
                                break;
                            }
                        }
                        for (int l = gongColumn * 3; l < gongColumn * 3 + 3; l++) {
                            if (l == k) {
                                if (arrAnswer[gongRow * 3][k] == 0 && arrAnswer[gongRow * 3 + 1][k] == 0 && arrAnswer[gongRow * 3 + 2][k] == 0)
                                    gongColumnNull = true;
                            } else if (checkColumn(num, l)) {
                                otherTwoColumnHas = false;
                                break;
                            }
                        }
                        //
                        if ((otherTwoRowHas && otherTwoColumnHas || otherTwoRowHas && !gongRowNull || otherTwoColumnHas && !gongColumnNull) && checkColumn(num, k) && checkRow(num, j) && checkGong(num, j, k)) {
                            list.add(new Block(j, k));
                        }
                    }
                }
            }
            listNumData.add(new NumData(num, list.size(), list));
//            List<Block> newList = new ArrayList<>();
//            for (int j = 0; j < list.size(); j++) {
//                Block block = list.get(j);
//                boolean unique = true;
//                for (int k = 0; k < list.size(); k++) {
//                    if (k == j) continue;
//                    Block temp = list.get(k);
//                    if ((temp.getX() == block.getX() || temp.getY() == block.getY()) && temp.getX() / 3 == block.getX() / 3 && temp.getY() / 3 == block.getY() / 3) {//同宫且同线
//                        unique = false;
//                        break;
//                    }
//                }
//                if (unique) newList.add(block);
//            }
            if (list.size() == 1) {
                Block block = list.get(0);
                arrAnswer[block.getX()][block.getY()] = num;
                step++;
            }
//            for (int j = 0; j < newList.size(); j++) {
//                Block block = newList.get(j);
//                arrAnswer[block.getX()][block.getY()] = num;
//                step++;
//            }
        }
        allStep += step;
        return step;
    }

    private void figureOut() {
        int step = getStep();
        if (step == 0) {
            if (!isSuccess(arrAnswer)) {
                poJie(arrAnswer);
//                if (Checker.hasList(listNumData)) {
//                    int nextNum = 0;
//                    int min = 99;
//                    for (int i = 0; i < listNumData.size(); i++) {
//                        NumData temp = listNumData.get(i);
//                        if (temp.getPositionNum() > 0 && temp.getPositionNum() < min) {
//                            min = temp.getPositionNum();
//                            nextNum = temp.getNum();
//                            numData = temp;
//                        }
//                    }
//                    if (allStep > lastStep) {
//                        lastStep = allStep;
//                        int size = listRecord.size();
//                        RecordBean recordBean = new RecordBean(size + 1, arrAnswer, numData);
//                        listRecord.add(recordBean);
//                        LogUtils.e("listRecord.add" + numData.toString());
//                        EventBus.getDefault().post(new TypeData<>(TypeDataNames.setRecord, new Records(listRecord)));
//                    }
//                    if (nextNum > 0) {
//                        ToastUtil.show("请设置下个数字" + nextNum + " 它有" + min + "种可能的位置");
//                        current = nextNum;
//                        invalidate();
//                    }
//                }
            } else {
                LogUtils.e("破解完成");
            }
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 9; i++) {
                for (int j = 0; j < 9; j++) {
                    sb.append(arrAnswer[i][j]);
                    if ((j + 1) % 3 == 0) sb.append(" ");
                }
                sb.append("\n");
                if ((i + 1) % 3 == 0) sb.append("\n");
            }
            sb.append("\n");
            LogUtils.e("破解结果：\n" + sb.toString());
        } else {
            ToastUtils.getInstance().showInfo("新破解+" + step);
            invalidate();
        }
    }

    private boolean isSuccess(int[][] arr) {
        boolean success = true;
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (arr[i][j] == 0) {
                    success = false;
                    break;
                }
            }
        }
        return success;
    }

    private boolean checkRow(int number, int row) {
        if (number < 1 || number > 9) return false;
        if (row < 0 || row > 8) return false;
        int[] a = arrAnswer[row];
        for (int i = 0; i < a.length; i++) {
            int num = a[i];
            if (num == 0) continue;
            if (num == number) return false;
        }
        return true;
    }

    private boolean checkColumn(int number, int column) {
        if (number < 1 || number > 9) return false;
        if (column < 0 || column > 8) return false;
        int[] a = new int[9];
        for (int i = 0; i < arrAnswer.length; i++) {
            a[i] = arrAnswer[i][column];
        }
        for (int i = 0; i < a.length; i++) {
            int num = a[i];
            if (num == 0) continue;
            if (num == number) return false;
        }
        return true;
    }

    private boolean checkGong(int number, int row, int column) {
        if (number < 1 || number > 9) return false;
        if (row < 0 || row > 8) return false;
        if (column < 0 || column > 8) return false;
        int[] a = new int[9];
        int index = 0;
        int gongRow = row / 3;
        int gongColumn = column / 3;
        for (int i = gongRow * 3; i < gongRow * 3 + 3; i++) {
            for (int j = gongColumn * 3; j < gongColumn * 3 + 3; j++) {
                a[index] = arrAnswer[i][j];
                index++;
            }
        }
        for (int i = 0; i < a.length; i++) {
            int num = a[i];
            if (num == 0) continue;
            if (num == number) return false;
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(colorWhite);
        if (blockLong <= 0) {
            blockLong = getWidth() / 11f;
        }
        //lines
        paint.setColor(colorGray);
        for (int i = 0; i < 10; i++) {
            paint.setStrokeWidth(i % 3 == 0 ? 6 : 3);
            //rows
            canvas.drawLine(blockLong, blockLong * (i + 1), getWidth() - blockLong, blockLong * (i + 1), paint);
            //columns
            canvas.drawLine(blockLong * (i + 1), blockLong, blockLong * (i + 1), getHeight() - blockLong, paint);
        }
        //bg of current number
        if (current > 0) {
            paint.setColor(colorGray);
            canvas.drawRoundRect(current * blockLong, getHeight() - blockLong, (current + 1) * blockLong, getHeight(), RADIUS, RADIUS, paint);
        }

        //tags
        textPaint.setColor(colorBlack);
        textPaintBold.setColor(colorBlack);
        for (int i = 0; i < rows.length; i++) {
            //rows
            textPaint.getTextBounds(rows[i], 0, rows[i].length(), rect);
            canvas.drawText(rows[i], blockLong / 2f - rect.width() / 2f, blockLong * (i + 1) + blockLong / 2f - (rect.bottom + rect.top) / 2f, textPaint);
            //columns
            String strColumn = String.valueOf(i + 1);
            textPaint.getTextBounds("4", 0, strColumn.length(), rect);
            canvas.drawText(strColumn, blockLong * (i + 1) + blockLong / 2f - rect.width() / 2f, blockLong / 2f - (rect.bottom + rect.top) / 2f, textPaint);
            textPaintBold.getTextBounds("4", 0, strColumn.length(), rect);
            canvas.drawText(strColumn, blockLong * (i + 1) + blockLong / 2f - rect.width() / 2f, getHeight() - blockLong / 2f - (rect.bottom + rect.top) / 2f, textPaintBold);
        }
        //btn
        String start = "破解";
        textPaint.getTextBounds(start, 0, start.length(), rect);
        canvas.drawText(start, getWidth() - blockLong + blockLong / 2f - rect.width() / 2f, blockLong / 2f - (rect.bottom + rect.top) / 2f, textPaint);
        //numbers
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                int number = arrTitle[i][j];
                if (number != 0) {//固定的题目已给的数字
                    textPaintBold.setColor(colorBlack);
                    String str = String.valueOf(number);
                    textPaintBold.getTextBounds(str.length() == 1 ? "4" : str, 0, str.length(), rect);
                    if (number == current)
                        canvas.drawRoundRect(blockLong * (j + 1), blockLong * (i + 1), blockLong * (j + 2), blockLong * (i + 2), RADIUS, RADIUS, paint);
                    canvas.drawText(str, blockLong * (j + 1) + blockLong / 2f - rect.width() / 2f, blockLong * (i + 1) + blockLong / 2f - (rect.bottom + rect.top) / 2f, textPaintBold);
                } else {//解答的数字，可以更改
                    int number2 = arrAnswer[i][j];
                    if (number2 != 0) {
                        textPaintBold.setColor(colorBlue);
                        String str = String.valueOf(number2);
                        textPaintBold.getTextBounds(str.length() == 1 ? "4" : str, 0, str.length(), rect);
                        if (number2 == current)
                            canvas.drawRoundRect(blockLong * (j + 1), blockLong * (i + 1), blockLong * (j + 2), blockLong * (i + 2), RADIUS, RADIUS, paint);
                        canvas.drawText(str, blockLong * (j + 1) + blockLong / 2f - rect.width() / 2f, blockLong * (i + 1) + blockLong / 2f - (rect.bottom + rect.top) / 2f, textPaintBold);
                    }
                }
            }
        }
        //待选
        if (Checker.notNull(numData)) {
            paint.setColor(colorGray2);
            List<Block> list = numData.getList();
            if (Checker.hasList(list)) {
                for (int i = 0; i < list.size(); i++) {
                    Block block = list.get(i);
                    canvas.drawRoundRect(blockLong * (block.getY() + 1), blockLong * (block.getX() + 1), blockLong * (block.getY() + 2), blockLong * (block.getX() + 2), RADIUS, RADIUS, paint);
                }
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        if (!editMode) return true;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                return true;
            case MotionEvent.ACTION_UP:
                if (y < blockLong) {//选择了第一行的按钮
                    if (x > getWidth() - blockLong) {
                        figureOut();
//                        new Thread(new Runnable() {
//                            @Override
//                            public void run() {
//                                poJie(arrAnswer);
//                            }
//                        }).start();
                    }
                    return true;
                } else if (y > getHeight() - blockLong) {//选择了某个数字将要填入
                    current = (int) (x / blockLong);
                    if (current < 1 || current > 9) return true;
//                    LogUtils.e("current = " + current);
                } else {//选择了某个格子，如果选择了数字则填入，否则提示先选择一个数字
                    if (current == 0) {
                        ToastUtils.getInstance().showInfo("请先选择一个数字");
                        return true;
                    }
                    int column = (int) (x / blockLong) - 1;
                    int row = (int) (y / blockLong) - 1;
                    if (column < 0) column = 0;
                    if (column > 8) column = 8;
                    if (row < 0) row = 0;
                    if (row > 8) row = 8;
//                    LogUtils.e("row_column = " + row + "_" + column);
                    if (arrAnswer[row][column] == 0) {
                        arrAnswer[row][column] = current;
                    } else {
                        arrAnswer[row][column] = 0;
                    }
                    numData = null;
                }
                invalidate();
                return true;
        }
        return super.onTouchEvent(event);
    }
}
